package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.OrderBusinessException;
import com.sky.mapper.*;
import com.sky.result.PageResult;
import com.sky.service.OrdersService;
import com.sky.utils.HttpClientUtil;
import com.sky.vo.*;
import com.sky.websocket.WebSocketServer;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class OrdersServiceImpl implements OrdersService {

    @Value("${sky.shop.address}")
    private String shopAddress;
    @Value("${sky.baidu.ak}")
    private String ak;

    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WebSocketServer webSocketServer;

    @Override
    public PageResult getHistoryOrders(OrdersPageQueryDTO ordersPageQueryDTO) {

        // 设置分页
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());

        // 构建查询参数
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());

        // 分页条件查询
        Page<Orders> page = ordersMapper.findByPage(ordersPageQueryDTO);

        List<OrderVO> list = new ArrayList();
        // 查询出订单明细，并封装入OrderVO进行响应
        if (page != null && page.getTotal() > 0) {
            for (Orders orders : page) {
                Long orderId = orders.getId();// 订单id
                // 查询订单明细
                List<OrderDetail> orderDetails = orderDetailMapper.getByOrderId(orderId);
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders, orderVO);
                orderVO.setOrderDetailList(orderDetails);
                list.add(orderVO);
            }
        }
        return new PageResult(page.getTotal(), list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderSubmitVO save(OrdersSubmitDTO ordersSubmitDTO) {

        Orders orders = Orders.builder().build();
        BeanUtils.copyProperties(ordersSubmitDTO, orders);

        Long userId = BaseContext.getCurrentId();
        orders.setUserId(userId);//储存用户id
        //拿到用户的购物车
        List<ShoppingCart> shoppingCarts = shoppingCartMapper.list(ShoppingCart.builder().userId(userId).build());
        if (null == shoppingCarts || shoppingCarts.size() == 0) {
            //购物车空说明有问题
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //储存订单
        //拿到当前用户信息
        User user = userMapper.getById(userId);

        //拿到地址
        AddressBook defaultAddress =
                addressBookMapper.getByDefault(AddressBook.builder().isDefault(1).userId(userId).build());
        //地址不能为空
        if (null == defaultAddress) throw new AddressBookBusinessException(MessageConstant.ADDRESS_BOOK_IS_NULL);
        //生成地址信息
        String address =
                defaultAddress.getProvinceName() + defaultAddress.getCityName() +
                        defaultAddress.getDistrictName() + defaultAddress.getDetail();
        //判断派送距离
        checkOutOfRange(address);

        orders.setAddress(address);//设置地址
        orders.setOrderTime(LocalDateTime.now());//设置订单生成时间
        String orderNumber = UUID.randomUUID().toString();
        orders.setNumber(orderNumber);
        orders.setStatus(Orders.PENDING_PAYMENT);//初始化订单状态
        orders.setPayStatus(Orders.UN_PAID);//初始化订单支付状态
        orders.setUserName(user.getName());//设置用户名
        orders.setPhone(user.getPhone());//设置手机号
        orders.setConsignee(defaultAddress.getConsignee());//设置收货人
        ordersMapper.save(orders);
        Long ordersId = orders.getId();

        for (ShoppingCart shoppingCart : shoppingCarts) {
            OrderDetail orderDetail = OrderDetail.builder().build();
            //储存订单详情信息
            if (shoppingCart.getDishId() != null) {
                //当前购物车是菜品
                orderDetail.setDishId(shoppingCart.getDishId());
            } else {
                //当前购物车是套餐
                orderDetail.setSetmealId(shoppingCart.getSetmealId());
            }
            orderDetail.setImage(shoppingCart.getImage());
            orderDetail.setAmount(shoppingCart.getAmount());
            orderDetail.setDishFlavor(shoppingCart.getDishFlavor());
            orderDetail.setName(shoppingCart.getName());
            orderDetail.setNumber(shoppingCart.getNumber());
            orderDetail.setOrderId(ordersId);
//            System.out.println(orderDetail);
            orderDetailMapper.save(orderDetail);//储存订单详情
            shoppingCartMapper.delete(shoppingCart);//删除当前购物车
        }
        //封装返回结果
        OrderSubmitVO orderSubmitVO = OrderSubmitVO.builder()
                .id(orders.getId())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .build();

        return orderSubmitVO;

    }

    @Override
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) {

        String orderNumber = ordersPaymentDTO.getOrderNumber();
        paySuccess(orderNumber);

        return new OrderPaymentVO();
    }

    @Override
    public void paySuccess(String outTradeNo) {

        Long userId = BaseContext.getCurrentId();
        //拿到对应支付的订单
        Orders orders1 = ordersMapper.findByUserIdAndNumber(userId, outTradeNo);

        Orders orders = Orders.builder()
                .id(orders1.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();
        //修改订单状态
        ordersMapper.update(orders);

        //增加动态推送消息
        Map<String, Object> map = new HashMap<>();
        map.put("type", 1);//消息类型，1表示来单提醒
        map.put("orderId", orders.getId());
        map.put("content", "订单号：" + outTradeNo);

        //通过WebSocket实现来单提醒，向客户端浏览器推送消息
        webSocketServer.sendToAllClient(JSON.toJSONString(map));

    }

    @Override
    public OrderVO getByOrderDetail(Long orderId) {

        // 根据id查询订单
        Orders orders = ordersMapper.findById(orderId);

        // 查询该订单对应的菜品/套餐明细
        List<OrderDetail> orderDetailList = orderDetailMapper.getByOrderId(orders.getId());

        // 将该订单及其详情封装到OrderVO并返回
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(orders, orderVO);
        orderVO.setOrderDetailList(orderDetailList);

        return orderVO;
    }

    @Override
    public void cancel(Long orderId) {

//        6已取消 订单取消原因  订单取消时间
        Orders orderDB = ordersMapper.findById(orderId);
        if (null == orderDB) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        //订单状态 1待付款 2待接单 3已接单 4派送中 5已完成 6已取消 7退款
        if (orderDB.getStatus() > 2) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = Orders.builder().build();
        orders.setId(orderId);

        orders.setStatus(Orders.CANCELLED);//改变订单状态
        orders.setCancelReason("用户取消");//取消原因
        orders.setCancelTime(LocalDateTime.now());//取消时间

        ordersMapper.update(orders);

    }

    /**
     * 检查客户的收货地址是否超出配送范围
     *
     * @param address
     */
    private void checkOutOfRange(String address) {
        Map map = new HashMap();
        map.put("address", shopAddress); //商铺的地址  shopAddress
        map.put("output", "json"); //返回json格式
        map.put("ak", ak); //appkey 百度平台中复制

        //获取店铺的经纬度坐标
        String shopCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

        JSONObject jsonObject = JSON.parseObject(shopCoordinate);
        if (!jsonObject.getString("status").equals("0")) {
            throw new OrderBusinessException("店铺地址解析失败");
        }

        //数据解析
        JSONObject location = jsonObject.getJSONObject("result").getJSONObject("location");
        String lat = location.getString("lat");
        String lng = location.getString("lng");
        //店铺经纬度坐标
        String shopLngLat = lat + "," + lng;

        map.put("address", address);
        //获取用户收货地址的经纬度坐标
        String userCoordinate = HttpClientUtil.doGet("https://api.map.baidu.com/geocoding/v3", map);

        jsonObject = JSON.parseObject(userCoordinate);
        if (!jsonObject.getString("status").equals("0")) {
            throw new OrderBusinessException("收货地址解析失败");
        }

        //数据解析
        location = jsonObject.getJSONObject("result").getJSONObject("location");
        lat = location.getString("lat");
        lng = location.getString("lng");
        //用户收货地址经纬度坐标
        String userLngLat = lat + "," + lng;

        map.put("origin", shopLngLat);
        map.put("destination", userLngLat);
        map.put("steps_info", "0");

        //路线规划
        String json = HttpClientUtil.doGet("https://api.map.baidu.com/directionlite/v1/driving", map);

        jsonObject = JSON.parseObject(json);
        if (!jsonObject.getString("status").equals("0")) {
            throw new OrderBusinessException("配送路线规划失败");
        }

        //数据解析
        JSONObject result = jsonObject.getJSONObject("result");
        JSONArray jsonArray = (JSONArray) result.get("routes");
        Integer distance = (Integer) ((JSONObject) jsonArray.get(0)).get("distance");

        if (distance > 5000) {
            //配送距离超过5000米
            throw new OrderBusinessException("超出配送范围" + (distance - 5000) / 1000 + "km");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void repetition(Long orderId) {

        Orders orders = ordersMapper.findById(orderId);
        if (null == orders) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        List<OrderDetail> detailList = orderDetailMapper.getByOrderId(orderId);
        if (null == detailList || detailList.size() == 0) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }
        for (OrderDetail orderDetail : detailList) {
            ShoppingCart shoppingCart = ShoppingCart.builder()
                    .userId(BaseContext.getCurrentId())
                    .image(orderDetail.getImage())
                    .name(orderDetail.getName())
                    .amount(orderDetail.getAmount())
                    .number(orderDetail.getNumber())
                    .dishFlavor(orderDetail.getDishFlavor())
                    .createTime(LocalDateTime.now()).build();
            if (orderDetail.getDishId() != null) {
                //是单品
                shoppingCart.setDishId(orderDetail.getDishId());
            } else {
                //是套餐
                shoppingCart.setSetmealId(orderDetail.getSetmealId());
            }

            shoppingCartMapper.insert(shoppingCart);
        }

        OrdersSubmitDTO ordersSubmitDTO = new OrdersSubmitDTO();
        BeanUtils.copyProperties(orders, ordersSubmitDTO);
        //预计到达时间默认后退一小时
        ordersSubmitDTO.setEstimatedDeliveryTime(LocalDateTime.now().plusHours(1));
        OrderSubmitVO save = save(ordersSubmitDTO);

    }

    @Override
    public PageResult getOrdersByCondition(OrdersPageQueryDTO ordersPageQueryDTO) {

        // 设置分页
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        // 构建查询参数
//        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        // 分页条件查询
        Page<Orders> page = ordersMapper.findByPage(ordersPageQueryDTO);

        List<OrderVO> list = new ArrayList();
        // 查询出订单明细，并封装入OrderVO进行响应
        if (page != null && page.getTotal() > 0) {
            for (Orders orders : page) {
                Long orderId = orders.getId();// 订单id
                // 查询订单明细
                List<OrderDetail> orderDetails = orderDetailMapper.getByOrderId(orderId);
                OrderVO orderVO = new OrderVO();
                BeanUtils.copyProperties(orders, orderVO);
                orderVO.setOrderDetailList(orderDetails);
                list.add(orderVO);
            }
        }
        return new PageResult(page.getTotal(), list);
    }

    @Override
    public void accept(OrdersDTO ordersDTO) {

        Orders orders = Orders.builder()
                .id(ordersDTO.getId())
                .status(Orders.CONFIRMED)
                .build();
        ordersMapper.update(orders);

    }

    @Override
    public OrderStatisticsVO statistics() {
        // 根据状态，分别查询出待接单、待派送、派送中的订单数量
        Integer toBeConfirmed = ordersMapper.countStatus(Orders.TO_BE_CONFIRMED);
        Integer confirmed = ordersMapper.countStatus(Orders.CONFIRMED);
        Integer deliveryInProgress = ordersMapper.countStatus(Orders.DELIVERY_IN_PROGRESS);

        // 将查询出的数据封装到orderStatisticsVO中响应
        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();
        orderStatisticsVO.setToBeConfirmed(toBeConfirmed);
        orderStatisticsVO.setConfirmed(confirmed);
        orderStatisticsVO.setDeliveryInProgress(deliveryInProgress);
        return orderStatisticsVO;
    }

    @Override
    public void cancelByAdmin(OrdersCancelDTO ordersCancelDTO) {
        // 根据id查询订单
        Orders ordersDB = ordersMapper.findById(ordersCancelDTO.getId());

        // 管理端取消订单需要退款，根据订单id更新订单状态、取消原因、取消时间
        Orders orders = new Orders();
        orders.setId(ordersCancelDTO.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelReason(ordersCancelDTO.getCancelReason());
        orders.setCancelTime(LocalDateTime.now());
        ordersMapper.update(orders);
    }

    @Override
    public void rejection(OrdersRejectionDTO ordersRejectionDTO) {
        // 根据id查询订单
        Orders ordersDB = ordersMapper.findById(ordersRejectionDTO.getId());

        // 订单只有存在且状态为2（待接单）才可以拒单
        if (ordersDB == null || !ordersDB.getStatus().equals(Orders.TO_BE_CONFIRMED)) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        // 拒单需要退款，根据订单id更新订单状态、拒单原因、取消时间
        Orders orders = new Orders();
        orders.setId(ordersDB.getId());
        orders.setStatus(Orders.CANCELLED);
        orders.setRejectionReason(ordersRejectionDTO.getRejectionReason());
        orders.setCancelTime(LocalDateTime.now());

        ordersMapper.update(orders);
    }

    public void delivery(Long id) {
        // 根据id查询订单
        Orders ordersDB = ordersMapper.findById(id);

        // 校验订单是否存在，并且状态为3
        if (ordersDB == null || !ordersDB.getStatus().equals(Orders.CONFIRMED)) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = new Orders();
        orders.setId(ordersDB.getId());
        // 更新订单状态,状态转为派送中
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);

        ordersMapper.update(orders);
    }

    @Override
    public void complete(Long id) {
        // 根据id查询订单
        Orders ordersDB = ordersMapper.findById(id);

        // 校验订单是否存在，并且状态为4
        if (ordersDB == null || !ordersDB.getStatus().equals(Orders.DELIVERY_IN_PROGRESS)) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Orders orders = new Orders();
        orders.setId(ordersDB.getId());
        // 更新订单状态,状态转为完成
        orders.setStatus(Orders.COMPLETED);
        orders.setDeliveryTime(LocalDateTime.now());

        ordersMapper.update(orders);
    }

    @Override
    public void reminder(Long id) {
        // 查询订单是否存在
        Orders orders = ordersMapper.findById(id);
        if (orders == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //基于WebSocket实现催单
        Map map = new HashMap();
        map.put("type", 2);//2代表用户催单
        map.put("orderId", id);
        map.put("content", "订单号：" + orders.getNumber());
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
    }
}
